// Copyright 2021 by 马万里. All rights reserved.
// 开发团队 ：   鸡中之霸
// 开发人员 ：   马万里
// 开发时间 ：   2021/2/24 11:21
// 文件名称 ：   handler.go
// 工程名称 ：   netpan
// 开发工具 ：   GoLand
//

package handler

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"johnsonsmile.cn/netpan/common"
	"johnsonsmile.cn/netpan/config"
	myDB "johnsonsmile.cn/netpan/db"
	"johnsonsmile.cn/netpan/meta"
	"johnsonsmile.cn/netpan/mq"
	"johnsonsmile.cn/netpan/store/oss"
	util "johnsonsmile.cn/netpan/utils"
	"net/http"
	"os"
	"strconv"
	"time"
)

// UploadSucHandler: 上传文件
func UploadHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		data, err := ioutil.ReadFile("./static/view/index.html")
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			io.WriteString(w, "Internal server error")
			return
		}
		io.WriteString(w, string(data))
	} else if r.Method == "POST" {
		// 接收文件流并存储到本地目录
		file, header, err := r.FormFile("file")
		if err != nil {
			fmt.Printf("Failed to get data, err: %s\n", err.Error())
			return
		}
		defer file.Close()
		fileMeta := &meta.FileMeta{
			FileSha1: "",
			FileName: header.Filename,
			FileSize: 0,
			Location: "./tmp/" + header.Filename,
			UploadAt: time.Now().Format("2006-01-02 15:04:05"),
		}
		//err = os.Mkdir("tmp", 0666)
		newFile, err := os.Create(fileMeta.Location)
		if err != nil {
			fmt.Printf("Failed to create file, err: %s\n", err)
			return
		}
		defer newFile.Close()
		fileMeta.FileSize, err = io.Copy(newFile, file)
		if err != nil {
			fmt.Printf("Failed to save data into file, err: %s\n", err)
			return
		}
		//newFile.Seek(0, 0)
		file.Seek(0, 0)
		fileMeta.FileSha1 = util.FileSha1(newFile)

		// 同时将文件写入到ceph
		//data, _ := ioutil.ReadAll(newFile)
		//bucket := ceph.GetCephBucket("userfile")
		//cephPath := "/ceph/" + fileMeta.FileSha1
		//_ = bucket.Put(cephPath, data, "octet-stream", s3.PublicRead)
		//fileMeta.Location = cephPath

		// 写入到oss
		ossPath := "netpan/" + fileMeta.FileSha1
		//err = oss.Bucket().PutObject(ossPath, file)
		//if err != nil {
		//	fmt.Println(err.Error())
		//	w.Write([]byte("Upload failed!"))
		//	return
		//}
		//fileMeta.Location = ossPath
		data := mq.TransferData{
			FileHash:      fileMeta.FileSha1,
			CurLocation:   fileMeta.Location,
			DestLocation:  ossPath,
			DestStoreType: common.StoreOSS,
		}
		pubData, _ := json.Marshal(data)
		suc := mq.Publish(
			config.TransExchangeName,
			config.TransOSSRoutingKey,
			pubData)
		if !suc {
			// TODO:
		}

		//meta.UpdateFileMeta(fileMeta)
		_ = meta.UpdateFileMetaDB(fileMeta, true)
		// TODO: 更新用户文件表记录
		r.ParseForm()
		username := r.Form.Get("username")
		success := myDB.OnUserFileUploadFinished(username, fileMeta.FileSha1, fileMeta.FileName, fileMeta.FileSize)

		// 重定向到成功的页面
		if success {
			http.Redirect(w, r, "/static/view/home.html", http.StatusFound)
		} else {
			w.Write([]byte("Upload Failed!"))
		}
	}
}

// UploadSucHandler: 上传已完成
func UploadSucHandler(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "Upload Success!")
}

// GetFileMetaHandler: 获取文件元信息
func GetFileMetaHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	filehash := r.Form["filehash"][0]
	//fileMeta := meta.GetFileMeta(filehash)
	fileMeta := meta.GetFileMetaDB(filehash)
	if fileMeta == nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	data, err := json.Marshal(fileMeta)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Write(data)
}

// FileQueryHandler: 获取多个文件元信息列表
func FileQueryHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()

	limitCnt, err := strconv.Atoi(r.Form.Get("limit"))
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	//fileMetas := meta.GetLastFileMetas(limitCnt)
	//fileMetas, err := meta.GetLastFileMetasDB(limitCnt)
	username := r.Form.Get("username")
	userfiles, err := myDB.QueryUserFileMetas(username, limitCnt)

	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	data, err := json.Marshal(userfiles)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Write(data)
}

// DownloadHandler: 根据filehash下载文件
func DownloadHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	fsha1 := r.Form.Get("filehash")
	//fileMeta := meta.GetFileMeta(fsha1)
	fileMeta := meta.GetFileMetaDB(fsha1)
	if fileMeta == nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	file, err := os.Open(fileMeta.Location)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	defer file.Close()
	data, err := ioutil.ReadAll(file)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-type", "application/octect-stream")
	w.Header().Set("Content-Disposition", "attachment; filename="+fileMeta.FileName)
	w.Write(data)
}

// FileMetaUpdateHandler: 更新元信息接口(重命名)
func FileMetaUpdateHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()

	opType := r.Form.Get("op")
	fileSha1 := r.Form.Get("filehash")
	newFileName := r.Form.Get("filename")

	// 目前只支持0操作也就是重命名
	if opType != "0" {
		fmt.Println(opType)
		w.WriteHeader(http.StatusForbidden)
		return
	}

	// 只支持post方法
	if r.Method != "POST" {
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	//curFileMeta := meta.GetFileMeta(fileSha1)
	curFileMeta := meta.GetFileMetaDB(fileSha1)
	if curFileMeta == nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	if curFileMeta == nil {
		w.WriteHeader(http.StatusNotFound)
		io.WriteString(w, fileSha1+":文件不存在")
		return
	}

	curFileMeta.FileName = newFileName
	// 上个版本不小心删除的
	//meta.UpdateFileMeta(curFileMeta)
	meta.UpdateFileMetaDB(curFileMeta, false)

	data, err := json.Marshal(curFileMeta)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusOK)
	w.Write(data)
}

// FileDeleteHandler: 根据传入的文件hash删除文件
func FileDeleteHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	fileSha1 := r.Form.Get("filehash")

	// 删除文件
	//fMeta := meta.GetFileMeta(fileSha1)
	fMeta := meta.GetFileMetaDB(fileSha1)
	if fMeta == nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	if fMeta == nil {
		w.WriteHeader(http.StatusNotFound)
		io.WriteString(w, fileSha1+":文件不存在")
		return
	}

	os.Remove(fMeta.Location)

	//meta.RemoveFileMeta(fileSha1)
	_ = meta.RemoveFileMetaDB(fileSha1)

	w.WriteHeader(http.StatusOK)
}

// TryFastUploadHandler: 尝试秒传接口
func TryFastUploadHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()

	// 1. 解析请求参数
	username := r.Form.Get("username")
	filehash := r.Form.Get("filehash")
	filename := r.Form.Get("filename")
	filesizeStr := r.Form.Get("filesize")

	// 2. 从文件表中查询相同hash的文件记录
	fileMeta, err := myDB.GetFileMeta(filehash)
	if err != nil {
		fmt.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	// 3. 查不到记录则返回秒传失败
	if fileMeta == nil {
		resp := util.RespMsg{
			Code: -1,
			Msg:  "秒传失败,请访问普通上传接口",
			Data: nil,
		}
		w.Write(resp.JSONBytes())
		return
	}

	// 4. 上传过则将文件信息写入用户文件表,返回成功
	filesize, err := strconv.Atoi(filesizeStr)
	if err != nil {
		resp := util.RespMsg{
			Code: -1,
			Msg:  "参数不正确,稍后重试",
			Data: nil,
		}
		w.Write(resp.JSONBytes())
		return
	}
	suc := myDB.OnUserFileUploadFinished(username, filehash, filename, int64(filesize))
	if suc {
		resp := util.RespMsg{
			Code: 0,
			Msg:  "秒传成功",
		}
		w.Write(resp.JSONBytes())
		return
	}
	resp := util.RespMsg{
		Code: -2,
		Msg:  "秒传失败,请稍后重试",
	}
	w.Write(resp.JSONBytes())

}

// DownloadURLHandler: 生成oss下载地址
func DownloadURLHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	filehash := r.Form.Get("filehash")
	// 从文件表查找记录
	row, _ := myDB.GetFileMeta(filehash)
	// TODO: 判断文件是在ceph还是OSS中
	signedUrl := oss.DownloadUrl(row.FileAddr.String, row.FileName.String)
	w.Write([]byte(signedUrl))
}
